package pers.vic.sso.client.filter;

import org.apache.commons.lang3.StringUtils;
import pers.vic.boot.base.tool.Tools;
import pers.vic.sso.common.constant.Oauth2Constant;
import pers.vic.sso.common.constant.SsoConstant;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.function.Consumer;

/**
 * 描述:
 *      退出登录过滤器：客户端不主动退出，而是跳转到sso server端 执行退出处理，然后sso端通过回调通知各个客户端分别退出；
 *      但是服务端调用的地址是登录时候携带的redirectUrl地址，可能是任何地址(除非限制回跳地址就是首页)
 * @author Vic.xu
 * @date 2021-11-04 10:51
 */
public class LogoutFilter extends BaseClientFilter {

    //登出成功后的回调
    private Consumer<String> afterLogout;

    public void setAfterLogout(Consumer<String> afterLogout) {
        this.afterLogout = afterLogout;
    }

    @Override
    public boolean isAccessAllowed(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String accessToken = getLogoutParam(request);
        //当被sso server重定向回来的时候 携带了登出标识，则销毁session
        if (StringUtils.isNotBlank(accessToken)) {
            logger.info("sso server回调客户销毁session, accessToken = {}", accessToken);
            if (afterLogout != null) {
                afterLogout.accept(accessToken);
            }
            destroySession(accessToken);
            //重定向到sso server的登录页面
            redirectLogin(request, response);
            return false;
        }
        //当是客户端发起退出请求的时候则携带当前项目的首页地址重定向到sso server 的logout
        if (clientLogoutUrl.equals(Tools.getRequestUrl(request))) {
            redirectLogout(request, response);
            return false;
        }

        return true;
    }

    @Override
    String getRedirectUrl(HttpServletRequest request) {
        return "/";
    }

    private void redirectLogout(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String serverLogoutUrl = new StringBuilder().append(getServerUrl()).append(SsoConstant.LOGOUT_URL).append("?")
                .append(Oauth2Constant.APP_ID).append("=").append(getAppId()).append("&")
                .append(SsoConstant.REDIRECT_URI).append("=")
                .append(URLEncoder.encode(Tools.getRootUrl(request), "utf-8")).toString();
        response.sendRedirect(serverLogoutUrl);
    }

    /**
     * 销毁本地session
     */
    private void destroySession(String accessToken) {
        final HttpSession session = getSessionMappingStorage().removeSessionByMappingId(accessToken);
        if (session != null) {
            session.invalidate();
        }
    }

    /**
     * 获取sso中心返回的退出标识
     */
    private String getLogoutParam(HttpServletRequest request) {
        return request.getHeader(SsoConstant.LOGOUT_PARAMETER_NAME);
    }
}
